package cube.utils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;

import cube.data.util.DataUtil;
import cube.data.util.ListUtil;
import cube.io.StreamUtil;
import cube.io.file.FileInputHandler;
import cube.io.file.FileOutputAppendHandler;
import cube.io.file.FileOutputWriteHandler;
import cube.io.file.FileReaderHandler;
import cube.io.file.zip.ZipUtil;

/**
 * 文件处理工具
 * 
 * @author abiao
 */
public class FileUtil {

    /**
     * 文件路径分隔符
     */
    public static final String SEP = File.separator;

    /**
     * 检查文件是否存在
     */
    public static boolean exist(String fileName) {
        if (fileName == null) {
            return false;
        }
        return exist(new File(fileName));
    }

    /**
     * 检查一堆文件是否存在
     */
    public static boolean exists(String... fileNames) {
        for (int i = 0; i < fileNames.length; i++) {
            if (!exist(fileNames[i])) {
                return false;
            }
        }
        return true;
    }

    /**
     * 检查文件是否存在
     */
    public static boolean exist(File file) {
        if (file == null) {
            return false;
        }
        return file.exists() && file.isFile();
    }

    /**
     * 检查目录是否存在
     */
    public static boolean existPath(String path) {
        if (path == null) {
            return false;
        }
        return existPath(new File(path));
    }

    /**
     * 检查目录是否存在
     */
    public static boolean existPath(File path) {
        if (path == null) {
            return false;
        }
        return path.exists() && path.isDirectory();
    }

    /**
     * 移动文件
     */
    public static void move(String srcFile, String dstFile) {
        rename(srcFile, dstFile);
    }

    /**
     * 重命名
     */
    public static void rename(String srcFile, String dstFile) {
        File src = new File(srcFile);
        if (!exist(srcFile)) {
            return;
        }
        File dst = new File(dstFile);
        src.renameTo(dst);
    }

    /**
     * 复制文件
     */
    public static void copy(String srcFile, String dstFile) {
        try {
            if (!exist(srcFile)) {
                return;
            }
            copy(new FileInputStream(srcFile), new FileOutputStream(dstFile));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 流通道复制
     */
    private static void copy(FileInputStream fis, FileOutputStream fos) {
        try {
            FileChannel src = fis.getChannel();
            FileChannel dst = fos.getChannel();
            src.transferTo(0, src.size(), dst);
            StreamUtil.close(src, dst);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 删除文件
     */
    public static void delete(String file) {
        if (!exist(file)) {
            return;
        }
        new File(file).delete();
    }

    /**
     * 获取目录下所有文件名字
     */
    public static String[] getPathFileNames(String path) {
        if (!existPath(path)) {
            return new String[0];
        }
        File filePath = new File(path);
        return filePath.list();
    }

    /**
     * 获取文件大小
     */
    public static long getSize(String fileName) {
        return new File(fileName).length();
    }

    /**
     * 读取文件字节
     */
    public static byte[] read(String fileName) {
        return new FileInputHandler<byte[]>(fileName) {
            public byte[] execute(FileInputStream fis) throws IOException {
                return read(fis, fis.available());
            }
        }.handle();
    }

    /**
     * 读取文件字节
     */
    public static byte[] read(String fileName, final int size) {
        return new FileInputHandler<byte[]>(fileName) {
            public byte[] execute(FileInputStream fis) throws IOException {
                return read(fis, size);
            }
        }.handle();
    }

    /**
     * 读取文件所有行
     */
    public static List<String> readLines(String fileName) {
        return new FileReaderHandler<List<String>>(fileName) {
            public List<String> execute(BufferedReader br) throws Exception {
                return readLines(br);
            }
        }.handle();
    }

    /**
     * 读取文件行
     */
    public static List<String> readLines(String fileName, final int size) {
        return new FileReaderHandler<List<String>>(fileName) {
            public List<String> execute(BufferedReader br) throws Exception {
                return readLines(br, size);
            }
        }.handle();
    }

    /**
     * 内容写入文件
     */
    public static void write(String fileName, String text) {
        write(fileName, text.getBytes());
    }

    /**
     * 字节写入文件
     */
    public static void write(String fileName, final byte[] data) {
        new FileOutputWriteHandler(fileName) {
            public Void execute(FileOutputStream fos) throws Exception {
                return write(fos, data);
            }
        }.handle();
    }

    /**
     * 内容追加文件
     */
    public static void append(String fileName, String text) {
        append(fileName, text.getBytes());
    }

    /**
     * 字节追加文件
     */
    public static void append(String fileName, final byte[] data) {
        new FileOutputAppendHandler(fileName) {
            public Void execute(FileOutputStream fos) throws Exception {
                return write(fos, data);
            }
        }.handle();
    }

    /**
     * 获取文件绝对路径
     */
    public static String getFilePath(String fileName) {
        return getFilePath(new File(fileName));
    }

    /**
     * 获取文件绝对路径
     */
    public static String getFilePath(File file) {
        if (!exist(file)) {
            return null;
        }
        return file.getAbsolutePath();
    }

    /**
     * linux文本文件转为win文本文件
     */
    public static void lnx2win(String lnxTextFile, String winTextFile) {
        byte[] lnxText = FileUtil.read(lnxTextFile);
        List<Byte> replaceList = new ArrayList<Byte>();
        for (int i = 0; i < lnxText.length; i++) {
            if (i != lnxText.length - 1 || lnxText[lnxText.length - 1] != 0x0a) {
                if (lnxText[i] == 0x0a && i != 0 && lnxText[i - 1] != 0x0d) {
                    replaceList.add((byte) 0x0d);
                }
                replaceList.add(lnxText[i]);
            }
        }
        FileUtil.write(winTextFile, ListUtil.list2bytes(replaceList));
    }

    /**
     * win文本文件转为linux文本文件
     */
    public static void win2lnx(String winTextFile, String lnxTextFile) {
        byte[] winText = FileUtil.read(winTextFile);
        List<Byte> replaceList = new ArrayList<Byte>();
        for (int i = 0; i < winText.length - 1; i++) {
            if (winText[i] == 0x0d && winText[i + 1] == 0x0a) {
                replaceList.add((byte) 0x0a);
                i++;
            } else {
                replaceList.add(winText[i]);
            }
        }
        FileUtil.write(lnxTextFile, ListUtil.list2bytes(replaceList));
    }

    /**
     * 获取文件名
     */
    public static String getBaseName(String file) {
        if (file == null) {
            return null;
        }
        int index1 = file.lastIndexOf("/");
        int index2 = file.lastIndexOf("\\");
        int index = DataUtil.max(index1, index2);
        if (index == -1) {
            return file;
        }
        return file.substring(index + 1);
    }

    /**
     * 获取文件目录名
     */
    public static String getDirName(String file) {
        if (file == null || !file.contains(SEP)) {
            return file;
        }
        return file.substring(0, file.lastIndexOf(SEP));
    }

    /**
     * 获取以分隔符结尾的路径格式
     */
    public static String formatPathEndWithSEP(String path) {
        if (path.endsWith(SEP)) {
            return path;
        }
        return path + SEP;
    }

    /**
     * 检测是否为目录
     */
    public static boolean isPath(String file) {
        if (file == null) {
            return false;
        }
        return new File(file).isDirectory();
    }

    /**
     * 创建目录（自动创建父级目录）
     */
    public static void mkdir(String dir) {
        if (dir != null) {
            new File(dir).mkdirs();
        }
    }

    /**
     * 解压zip中指定文件到path路径
     */
    public static void unzip(String zip, String file, String path) {
        ZipUtil.unzip(zip, file, path);
    }

    /**
     * 解压zip中指定文件到path路径
     */
    public static void unzip(String zip, String[] files, String path) {
        ZipUtil.unzip(zip, files, path);
    }

    /**
     * 读取和class文件同级的资源文件
     */
    public static byte[] read(Class<?> clazz, String fileName) {
        byte[] data = null;
        try {
            InputStream is = clazz.getResourceAsStream(fileName);
            if (is != null) {
                data = new byte[is.available()];
                is.read(data);
                is.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return data;
    }

    /**
     * 对象序列化到文件
     */
    public static void writeObject(Object o, String fileName) {
        write(fileName, BeanUtil.object2bytes(o));
    }

    /**
     * 文件反序列化微对象
     */
    public static Object readObject(String fileName) {
        return BeanUtil.bytes2object(read(fileName));
    }

    /**
     * 按照文本内容进行读取
     */
    public static String readText(String fileName) {
        return new String(read(fileName));
    }
}
